package ldh.im.fxgui.controller.sub;

import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXDialog;
import com.jfoenix.controls.JFXDialogLayout;
import javafx.beans.property.BooleanProperty;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.geometry.Pos;
import javafx.geometry.Rectangle2D;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.RadioButton;
import javafx.scene.input.*;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.*;
import ldh.im.dto.enums.MessageType;
import ldh.im.fxbase.data.pojo.*;
import ldh.im.fxbase.data.pojo.status.ImMessageStatus;
import ldh.im.fxbase.data.pojo.status.ImSessionStatus;
import ldh.im.fxbase.service.*;
import ldh.im.fxgui.controller.*;
import ldh.im.fxgui.handle.IMessageEditorHandler;
import ldh.im.fxbase.util.*;
import ldh.im.fxgui.component.ImStage;
import ldh.im.fxgui.component.ScrollImTextArea;
import ldh.im.fxgui.handle.WebRtcClient;
import ldh.im.fxgui.pane.MessagePaneEnum;
import ldh.im.fxgui.service.MessageSendService;
import ldh.im.fxgui.stage.AudioStage;
import ldh.im.fxgui.stage.VideoStage;
import ldh.im.fxgui.util.ImSingleton;
import ldh.im.fxgui.util.UiUtil;
import ldh.im.util.ConfigUtil;
import ldh.im.util.Sets;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Closeable;
import java.io.File;
import java.net.URL;
import java.text.NumberFormat;
import java.util.*;
import java.util.stream.Collectors;

public class MessageEditorController implements IMessageEditorHandler, Initializable {

    private static final Logger LOGGER = LoggerFactory.getLogger(MessageEditorController.class);

    @FXML private ScrollImTextArea messageEditor;
    @FXML private Pane refMessagePane;
    @FXML private Pane refContainer;
    @FXML private Button sendMsgBtn;
    @FXML private Label cutSettingBtn;
    @FXML private Pane editorPane;

    private JFXDialog audioDialog = null;
    private FileChooser fileChooser = new FileChooser();
    private StackPane dialogRoot;

    // 消息框的popup
    private Popup editorPopup = new Popup();
    private VBox editorPopupPane = null;

    // 截图使用的参数
    private Popup popup = new Popup();     // 图片剪辑
    private VBox cutPopupPane = null;
    private volatile boolean isHideStage = true;
    private BooleanProperty settingPaneShowProperty;

    private MessageSendController messageSendController;

    private ImMessage refMessage = null;
    private ImSession currentSession;
    private Stage recordStage = null;  // 桌面录制Stage

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        editorPopup.setAutoHide(true);
        buildMessageEditorPopup();

        cleanRefMessage(null);

        messageEditor.getTextArea().requestFocus();

        fileChooser.setInitialDirectory(new File(System.getProperty("user.dir")));
        fileChooser.setSelectedExtensionFilter(new FileChooser.ExtensionFilter("im文件上传器",
                Arrays.asList("*.txt", "*.jpg", "*.png", "*.gif", "*.svg", "*.vsd", "*.gz", "*.zip", "*.rar",
                        "*.doc", "*.docx",  "*.xls", "*.xlsx", "*.ppt")));

        popup.setAutoHide(true);

        refMessagePane.setMaxHeight(30);

        bindEvent();
    }

    @Override
    public void setEditorText(String content) {
        messageEditor.getTextArea().setImData(content);
    }

    @Override
    public void setRefMessage(ImMessage message) {
        this.refMessage = message;
        Node refNode = MessagePaneEnum.getByMessageType(message.getMessageType()).getMessagePane().createRefPane(message, true);
        refMessagePane.getChildren().setAll(refNode);
        StackPane.setAlignment(refNode, Pos.CENTER_LEFT);
        refContainer.setManaged(true);
        refContainer.setVisible(true);
    }

    public void show() {
        editorPane.setVisible(true);
    }

    public void hide() {
        editorPane.setVisible(false);
    }

    public void requestFocus() {
        messageEditor.getTextArea().requestFocus();
    }

    public void setImSession(ImSession imSession) {
        this.currentSession = imSession;
    }

    public void setDialogRoot(StackPane root) {
        dialogRoot = root;
    }

    public void setMessageSendController(MessageSendController messageSendController) {
        this.messageSendController = messageSendController;
    }

    public void setSettingPaneShowProperty(BooleanProperty settingPaneShowProperty) {
        this.settingPaneShowProperty = settingPaneShowProperty;
    }

    @FXML
    public void sendMsg(ActionEvent actionEvent) {
        String msg = messageEditor.getTextArea().getData();
        if (messageEditor.getTextArea().isTooLength(msg)) {
            DialogUtil.alert("文本超长", "填入的数字太长");
            return ;
        }
        if (currentSession.getStatus() == ImSessionStatus.disable) {
            DialogUtil.alert("提醒", "此群已经解散，不能再发送消息");
            return ;
        }

        SensitiveWordService sensitiveWordService = BeanFactory.getInstance().getBean(SensitiveWordService.class);
        MessageSendService messageSendService = BeanFactory.getInstance().getBean(MessageSendService.class);

        if (sensitiveWordService.haveSensitiveWords(msg)) {
            DialogUtil.alert("提醒", "包含敏感信息");
            return ;
        }

        LOGGER.info("send message {}", msg);
        List<ImMessage> imMessages = messageSendService.buildMessages(currentSession, msg, refMessage);
        if (imMessages.size() < 1) return;

        sendMsgBtn.setDisable(true);

        messageSendController.showMessages(currentSession, imMessages);

        Task task = messageSendService.sendMessage(currentSession, imMessages);
        doTaskStatus(task, imMessages);
    }

    // 显示Emoji选择面板
    @FXML
    public void showEmojiPane(ActionEvent actionEvent) {
        Button b = (Button) actionEvent.getSource();
        UiUtil.getEmojiPane().show(b, emojiSpan->{
            if (currentSession.getStatus() == ImSessionStatus.disable) {
                DialogUtil.alert("提醒", "此群已经解散，不能再发送消息");
                return ;
            }
            messageEditor.getTextArea().insertEmoji(emojiSpan);
        });
    }

    // 上传文件
    @FXML
    public void uploadFile(ActionEvent actionEvent) {
        if (currentSession.getStatus() == ImSessionStatus.disable) {
            DialogUtil.alert("提醒", "此群已经解散，不能在发送消息");
            return ;
        }
        File file = fileChooser.showOpenDialog(sendMsgBtn.getScene().getWindow());
        if (file == null) return;
        ImMessage message = null;

        MessageSendService messageSendService = BeanFactory.getInstance().getBean(MessageSendService.class);
        if (FileUtil.isImage(file)) {
            message = messageSendService.buildMessage(currentSession, file.getPath(), MessageType.Image, refMessage);
        } else if (FileUtil.isAudio(file)) {
            message = messageSendService.buildMessage(currentSession, file.getPath(), MessageType.Audio, refMessage);
            message.getMessageExt().setTime(AudioUtil.calcAudioTime(file.getPath()));
            message.initExt();
        } else if (FileUtil.isVideo(file)) {
            message = messageSendService.buildMessage(currentSession, file.getPath(), MessageType.Video, refMessage);
        } else {
            message = messageSendService.buildMessage(currentSession, file.getPath(), MessageType.File, refMessage);
        }

        List<ImMessage> imMessages = new ArrayList<>();
        imMessages.add(message);
        messageSendController.showMessages(currentSession, imMessages);
        Task task = messageSendService.sendMessage(currentSession, imMessages);
        doTaskStatus(task, imMessages);
    }

    // 截图
    @FXML
    public void cut() {
        UiUtil.getScreenCapturePane().setParentStage((Stage)sendMsgBtn.getScene().getWindow());
        UiUtil.getScreenCapturePane().show(imagePath->{
            if (currentSession.getStatus() == ImSessionStatus.disable) {
                DialogUtil.alert("提醒", "此群已经解散，不能再发送截图");
                return ;
            }

            MessageSendService messageSendService = BeanFactory.getInstance().getBean(MessageSendService.class);
            ImMessage imMessage = messageSendService.buildMessage(currentSession, imagePath, MessageType.Image, refMessage);
            currentSession.setLatelyMessage("图片");
            List<ImMessage> imMessages = new ArrayList<>();
            imMessages.add(imMessage);

            messageSendController.showMessages(currentSession, imMessages);
            Task task = messageSendService.sendMessage(currentSession, imMessages);
            doTaskStatus(task, imMessages);
        }, isHideStage);
    }

    @FXML
    public void showCutSettingPopup() {
        buildCutPopupPane();
        double x = RegionUtil.calcAnchorX(cutSettingBtn, PopupPos.down_east, cutSettingBtn) + cutSettingBtn.getWidth();
        double y = RegionUtil.calcAnchorY(cutSettingBtn, PopupPos.down_east, cutSettingBtn);
        popup.getContent().clear();
        popup.getContent().add(cutPopupPane);
        popup.show(cutSettingBtn.getScene().getWindow(), x, y);
    }

    // 历史信息
    @FXML
    public void historyMessagePane(ActionEvent actionEvent) {
        String fxml = "/fxml/sub/HistoryMessagePane.fxml";
        RegionUtil.FxmlBean<VBox, HistoryMessageController> fxmlBean = SoftMapUtil.getCache(fxml);
        if (fxmlBean == null) {
            fxmlBean = RegionUtil.loadFxmlBean(this.getClass().getResource(fxml));
        }
        fxmlBean.getController().setImSession(currentSession);
        ImStage stage = new ImStage(500, 700);
        Scene scene = stage.getCurrentScene();
        scene.getStylesheets().add(this.getClass().getResource("/css/var.css").toExternalForm());
        scene.getStylesheets().add(this.getClass().getResource("/css/bootstrapfx.css").toExternalForm());
        scene.getStylesheets().add(this.getClass().getResource("/css/message-dialog.css").toExternalForm());
        scene.getStylesheets().add(this.getClass().getResource("/css/scrollbar.css").toExternalForm());
        scene.getStylesheets().add(this.getClass().getResource("/css/pagination.css").toExternalForm());
        stage.setContent(fxmlBean.getNode());

        stage.setTitle(currentSession.getName());
        stage.show();
    }

    // 视频聊天
    @FXML
    public void videoPane(ActionEvent actionEvent) {
        Closeable closeable = CloseFactory.getInstance().getCloseable("videoRoomStage");
        if (closeable != null) {
            DialogUtil.alert("错误", "当前已经有一个视频通信，结束后才能开启新的视频聊天窗口");
            return;
        }
        openVideoPane(null);
    }

    // 语音聊天
    @FXML
    public void audioPane(ActionEvent actionEvent) {
        Closeable closeable = CloseFactory.getInstance().getCloseable("audioRoomStage");
        if (closeable != null) {
            DialogUtil.alert("错误", "当前已经有一个视频通信，结束后才能开启新的视频聊天窗口");
            return;
        }
        openAudioPane(null);
    }

    // 录制语音
    @FXML public void audioSavePane(ActionEvent actionEvent) {
        if (!AudioUtil.checkHaveMicrophone()) {
            DialogUtil.alert("提醒", "没有麦克风，不支持录音");
            return;
        }

        AudioRecordService audioRecordService = new AudioRecordService(ImSingleton.getInstance().getLoginImUser().getUserId(), ConfigUtil.getRoot());
        MessageSendService messageSendService = BeanFactory.getInstance().getBean(MessageSendService.class);

        if (audioDialog == null) {
            JFXDialogLayout messge = new JFXDialogLayout();
            VBox vBox = new VBox();
            vBox.setSpacing(10);
            vBox.setAlignment(Pos.CENTER);
            Text text =  new Text();
            text.setFont(Font.font(20));
            audioRecordService.getRecordTimeProperty().addListener(l->{
                long time = audioRecordService.getRecordTime();
                NumberFormat numberFormat = NumberFormat.getNumberInstance();
                numberFormat.setMaximumFractionDigits(1);
                text.setText(numberFormat.format((double)time/1000) + " 秒");
            });
            Button b = new Button("Start");
            b.setStyle("-fx-background-color: cadetblue;"+
                    "-fx-background-radius: 20;"+
                    "-fx-text-fill: antiquewhite;"+
                    "-fx-font-family: 'Microsoft YaHei UI';"+
                    "-fx-font-size: 20"
            );
            b.setOnAction(e->{
                try {
                    if (b.getText().equals("Start")) {
                        audioRecordService.startRecord();
                        b.setText("Stop");
                    } else {
                        b.setText("Start");
                        audioRecordService.stopRecord();

                        File file = new File(audioRecordService.getAudioFile());
                        long fileSize = FileUtil.getFileSize(file);
                        if (fileSize > 1000) {
                            ImMessage imMessage = messageSendService.buildMessage(currentSession, file.getPath(), MessageType.Audio, refMessage);
                            imMessage.getMessageExt().setTime((int)audioRecordService.getRecordTime());
                            imMessage.initExt();

                            List<ImMessage> imMessages = Arrays.asList(imMessage);
                            messageSendController.showMessages(currentSession, imMessages);
                            messageSendService.sendMessage(currentSession, imMessages);
                        }

                        audioDialog.close();
                    }
                } catch (Exception exception) {
                    LOGGER.error("语音录制失败, {}", exception);
                }
            });
            vBox.getChildren().addAll(text, b);
            messge.setBody(vBox);
            audioDialog = new JFXDialog(dialogRoot, messge, JFXDialog.DialogTransition.CENTER);
            audioDialog.setPrefSize(200, 80);
            audioDialog.setMaxSize(200, 80);
        }
        audioDialog.show();
        audioRecordService.getRecordTimeProperty().set(0);
    }

    // 录制屏幕
    @FXML
    private void recordScreenPane(ActionEvent actionEvent) {
        if (recordStage != null) {
            recordStage.setIconified(false);
            recordStage.setAlwaysOnTop(true);
            recordStage.show();
            return;
        }
        StageUtil.getStage().setIconified(true);

        recordStage = new Stage();
        recordStage.setAlwaysOnTop(true);
        recordStage.initStyle(StageStyle.TRANSPARENT);
        RegionUtil.FxmlBean<Pane, RecordScreenController> fxmlBean = RegionUtil.loadFxmlBean(this.getClass().getResource("/fxml/sub/RecordScreenPane.fxml"));
        MovableHelper.movable(fxmlBean.getNode());
        fxmlBean.getController().setCloseCallback((stage)->{
            recordStage.close();
            recordStage = null;
        });
        fxmlBean.getController().setHandleGifCallback(this::sendGifMessageEvent);
        Scene scene = new Scene(fxmlBean.getNode(), 130, 150);
        scene.setFill(null);
        scene.getStylesheets().add(this.getClass().getResource("/css/var.css").toExternalForm());
        scene.getStylesheets().add(this.getClass().getResource("/css/record-pane.css").toExternalForm());
        recordStage.setScene(scene);
        Rectangle2D rectangle2D = Screen.getPrimary().getBounds();
        recordStage.setX(rectangle2D.getWidth()-scene.getWidth()-10);
        recordStage.setY(rectangle2D.getHeight()/4);

        fxmlBean.getController().setStage(recordStage);
        recordStage.show();

    }

    @FXML
    private void cleanRefMessage(MouseEvent mouseEvent) {
        refMessagePane.getChildren().clear();
        refContainer.setVisible(false);
        refContainer.setManaged(false);
        refMessage = null;
    }

    private void openAudioPane(String groupId) {
        if (currentSession.getFromUserId().equals(currentSession.getToUserId())) {
            DialogUtil.alert(dialogRoot, "提示", "不能自己对自己语音和视频");
            return;
        }
//        if (!AudioUtil.checkHaveMicrophone()) {
//            DialogUtil.alert("提醒", "没有麦克风，不支持语音聊天");
//            return;
//        }

        if (!currentSession.isP2p()) {
            RegionUtil.FxmlBean<Pane, SelectGroupUserController> fxmlBean = RegionUtil.loadFxmlBean(this.getClass().getResource("/fxml/sub/SelectGroupUserPane.fxml"));
            JFXDialog dialog = DialogUtil.show(dialogRoot, fxmlBean.getNode(), false);
            dialog.setPrefSize(700, 450);
            fxmlBean.getController().setParams(dialog, currentSession, selectGroupUsers->{
                if (selectGroupUsers.size() > WebRtcClient.MAX_USER_LIMIT) {
                    DialogUtil.alert("警告", String.format("视频群聊最多不能超过%s人", WebRtcClient.MAX_USER_LIMIT));
                    return;
                }
                AudioStage audioStage = new AudioStage("audioRoomStage");
                audioStage.doOpenAudioPane(null, groupId,
                        selectGroupUsers.stream().map(gu->gu.getUserId()).collect(Collectors.toSet()));
            });
            return;
        }
        AudioStage audioStage = new AudioStage("audioRoomStage");
        audioStage.doOpenAudioPane(null, groupId, Sets.asSet(currentSession.getToUserId(), currentSession.getFromUserId()));
    }

    private void openVideoPane(String roomName) {
        if (currentSession.getFromUserId().equals(currentSession.getToUserId())) {
            DialogUtil.alert(dialogRoot, "提示", "不能自己对自己语音和视频");
            return;
        }
//        if (!AudioUtil.checkHaveCamera()) {
//            DialogUtil.alert("提醒", "没有摄像设备，不支持视频聊天");
//            return ;
//        }

        if (!currentSession.isP2p() && roomName == null) {
            RegionUtil.FxmlBean<Pane, SelectGroupUserController> fxmlBean = RegionUtil.loadFxmlBean(this.getClass().getResource("/fxml/sub/SelectGroupUserPane.fxml"));
            JFXDialog dialog = DialogUtil.show(dialogRoot, fxmlBean.getNode(), false);
            dialog.setPrefSize(700, 450);
            fxmlBean.getController().setParams(dialog, currentSession, selectGroupUsers->{
                if (selectGroupUsers.size() > WebRtcClient.MAX_USER_LIMIT) {
                    DialogUtil.alert("警告", String.format("视频群聊最多不能超过%s人", WebRtcClient.MAX_USER_LIMIT));
                    return;
                }
                VideoStage videoStage = new VideoStage("videoRoomStage");
                videoStage.doOpenVideoPane(null, roomName,
                        selectGroupUsers.stream().map(gu->gu.getUserId()).collect(Collectors.toSet()));
            });
            return;
        }
        VideoStage videoStage = new VideoStage("videoRoomStage");
        videoStage.doOpenVideoPane(null, roomName, Sets.asSet(currentSession.getToUserId(), currentSession.getFromUserId()));
    }

    private void bindEvent() {
        messageEditor.getTextArea().setOnMousePressed(e->{
            if (e.getButton() == MouseButton.SECONDARY) {
                double x = e.getScreenX();
                double y = e.getScreenY();
                editorPopup.getContent().clear();
                editorPopup.getContent().add(editorPopupPane);
                editorPopup.show(messageEditor.getScene().getWindow(), x, y);
            }
            settingPaneShowProperty.set(false);
        });

        messageEditor.getTextArea().setOnKeyPressed(e->{
            if (e.getCode() == KeyCode.UP) {
                messageSendController.upEvent();
            } else if (e.getCode() == KeyCode.DOWN) {
                messageSendController.downEvent();
            }
        });

        // 消息发送按钮的快捷键
        KeyCodeCombination sendButtonKey = new KeyCodeCombination(KeyCode.S, KeyCombination.ALT_ANY);
        StageUtil.getStage().getScene().getAccelerators().put(sendButtonKey, ()->{
            sendMsgBtn.fire();
        });

        // Ctr + Enter 也可以发送消息
        KeyCodeCombination ctrEnterKey = new KeyCodeCombination(KeyCode.ENTER, KeyCombination.CONTROL_DOWN);
        StageUtil.getStage().getScene().getAccelerators().put(ctrEnterKey, ()->{
            sendMsgBtn.fire();
        });
    }

    private void buildCutPopupPane() {
        if (cutPopupPane != null) return;
        cutPopupPane = new VBox();
        cutPopupPane.getStyleClass().add("cut-popup-pane");
        RadioButton radioButton = new RadioButton("截图时不隐藏当前窗口");
        cutPopupPane.getChildren().add(radioButton);
        radioButton.selectedProperty().addListener(b->{
            isHideStage = !radioButton.isSelected();
        });
    }

    private void buildMessageEditorPopup() {
        if (editorPopupPane != null) return;
        editorPopupPane = new VBox();
        editorPopupPane.getStyleClass().add("editor-popup-pane");
        JFXButton copyBtn = new JFXButton("粘贴");
        copyBtn.getStyleClass().add("btn-lg");
        editorPopupPane.getChildren().add(copyBtn);
        copyBtn.setOnAction(e->{
            messageEditor.getTextArea().paste();
            editorPopup.hide();
        });
    }

    private void doTaskStatus(Task task, List<ImMessage> imMessages) {
        task.progressProperty().addListener(l->{
            if (Double.compare(task.getProgress(), 0.3d) >= 0) {
                messageEditor.getTextArea().clear();
                messageSendController.reloadSession(currentSession);
            }
        });
        task.setOnSucceeded(s->{
            sendMsgBtn.setDisable(false);
            cleanRefMessage(null);
        });
        task.setOnFailed(e->{
            sendMsgBtn.setDisable(false);
            imMessages.stream().forEach(message->message.setStatus(ImMessageStatus.failure));
            UiUtil.uiUpdateMessages(imMessages);
            LOGGER.error("发送消息失败", task.getException());
            DialogUtil.alert("错误", "发送消息失败");
        });
    }

    // 发送录屏事件
    private void sendGifMessageEvent(String imagePath, MessageType messageType) {
        FxThreadUtil.runLater(()->{
            StageUtil.getStage().setIconified(false);
            StageUtil.getStage().show();
        });

        if (currentSession.getStatus() == ImSessionStatus.disable) {
            FxThreadUtil.runLater(()->{
                DialogUtil.alert("提醒", "此群已经解散，不能再发送截图");
            });
            return ;
        }

        MessageSendService messageSendService = BeanFactory.getInstance().getBean(MessageSendService.class);
        ImMessage imMessage = messageSendService.buildMessage(currentSession, imagePath, messageType, refMessage);
        currentSession.setLatelyMessage("图片");
        List<ImMessage> imMessages = new ArrayList<>();
        imMessages.add(imMessage);

        messageSendController.showMessages(currentSession, imMessages);
        Task task = messageSendService.sendMessage(currentSession, imMessages);
        FxThreadUtil.runLater(()->{
            doTaskStatus(task, imMessages);
        });
    }

}
